//
//  TestNewSpec.m
//  LogicSim
//
//  Created by Jeremy Pereira on 12/02/2013.
//
//

#import "TestNewSpec.h"
#import "LGSConnectionContext.h"
#import "LGSAndGate.h"
#import "LGSOrGate.h"
#import "LGSXorGate.h"
#import "LGSModule.h"
#import "LGSEdge.h"
#import "LGSName.h"

@implementation TestNewSpec

-(void) testCreateAnd
{
    NSString* testString = @""
    "   {"
    "\"name\" : \"something\","
    "\"nodeType\" : \"LGSAndGate\""
	"}";
    
    NSData* jsonData = [testString dataUsingEncoding: NSUTF8StringEncoding];
    NSError* error = nil;
    id jsonObject = [NSJSONSerialization JSONObjectWithData: jsonData
                                                    options: 0
                                                      error: &error];
    NSAssert1(jsonObject != nil, @"Invalid JSON string, %@", error);
    NSAssert1([jsonObject isKindOfClass: [NSDictionary class]],
              @"Invalid JSON object, %@", jsonObject);
    LGSConnectionContext* connectionContext = [[LGSConnectionContext alloc] init];
    id deserialisedNode = [LGSNode makeNodeFromDictionary: jsonObject
                                        connectionContext: connectionContext
                                                    error: &error];
    STAssertNotNil(deserialisedNode, @"Failed to deserialise, error %@", error);
    STAssertTrue([deserialisedNode isKindOfClass: [LGSAndGate class]],
                 @"Incorrect type %@",
                 deserialisedNode);
	STAssertNotNil([connectionContext nodeForName: [LGSName nameWithString: @"something"]],
                   @"Node not added to connection context");
    NSArray* inputNames = [deserialisedNode inputNames];
    STAssertTrue([inputNames count] == 2, @"Input names has wrong count %@", inputNames);
    STAssertTrue([inputNames containsObject: [LGSName nameWithConnectionString: @"a"]],
                 @"Input names has no a %@",
                 inputNames);
    STAssertTrue([inputNames containsObject: [LGSName nameWithConnectionString: @"b"]],
                 @"Input names has no b %@",
                 inputNames);
    NSArray* outputNames = [deserialisedNode outputNames];
    STAssertTrue([outputNames count] == 1, @"Output names has wrong count %@", outputNames);
    STAssertTrue([outputNames containsObject: [LGSName nameWithConnectionString: @"output"]],
                 @"Output names has no output %@",
                 outputNames);
}

-(void) testCreateOr
{
    NSString* testString = @""
    "   {"
    "\"name\" : \"something\","
    "\"nodeType\" : \"LGSOrGate\""
	"}";
    
    NSData* jsonData = [testString dataUsingEncoding: NSUTF8StringEncoding];
    NSError* error = nil;
    id jsonObject = [NSJSONSerialization JSONObjectWithData: jsonData
                                                    options: 0
                                                      error: &error];
    NSAssert1(jsonObject != nil, @"Invalid JSON string, %@", error);
    NSAssert1([jsonObject isKindOfClass: [NSDictionary class]],
              @"Invalid JSON object, %@", jsonObject);
    LGSConnectionContext* connectionContext = [[LGSConnectionContext alloc] init];
    id deserialisedNode = [LGSNode makeNodeFromDictionary: jsonObject
                                        connectionContext: connectionContext
                                                    error: &error];
    STAssertNotNil(deserialisedNode, @"Failed to deserialise, error %@", error);
    STAssertTrue([deserialisedNode isKindOfClass: [LGSOrGate class]],
                 @"Incorrect type %@",
                 deserialisedNode);
	STAssertNotNil([connectionContext nodeForName: [LGSName nameWithString: @"something"]],
                   @"Node not added to connection context");
    NSArray* inputNames = [deserialisedNode inputNames];
    STAssertTrue([inputNames count] == 2, @"Input names has wrong count %@", inputNames);
    STAssertTrue([inputNames containsObject: [LGSName nameWithConnectionString: @"a"]],
                 @"Input names has no a %@",
                 inputNames);
    STAssertTrue([inputNames containsObject: [LGSName nameWithConnectionString: @"b"]],
                 @"Input names has no b %@",
                 inputNames);
    NSArray* outputNames = [deserialisedNode outputNames];
    STAssertTrue([outputNames count] == 1, @"Output names has wrong count %@", outputNames);
    STAssertTrue([outputNames containsObject: [LGSName nameWithConnectionString: @"output"]],
                 @"Output names has no output %@",
                 outputNames);
}

-(void) testCreateXor
{
    NSString* testString = @""
    "   {"
    "\"name\" : \"something\","
    "\"nodeType\" : \"LGSXorGate\""
	"}";
    
    NSData* jsonData = [testString dataUsingEncoding: NSUTF8StringEncoding];
    NSError* error = nil;
    id jsonObject = [NSJSONSerialization JSONObjectWithData: jsonData
                                                    options: 0
                                                      error: &error];
    NSAssert1(jsonObject != nil, @"Invalid JSON string, %@", error);
    NSAssert1([jsonObject isKindOfClass: [NSDictionary class]],
              @"Invalid JSON object, %@", jsonObject);
    LGSConnectionContext* connectionContext = [[LGSConnectionContext alloc] init];
    id deserialisedNode = [LGSNode makeNodeFromDictionary: jsonObject
                                        connectionContext: connectionContext
                                                    error: &error];
    STAssertNotNil(deserialisedNode, @"Failed to deserialise, error %@", error);
    STAssertTrue([deserialisedNode isKindOfClass: [LGSXorGate class]],
                 @"Incorrect type %@",
                 deserialisedNode);
	STAssertNotNil([connectionContext nodeForName: [LGSName nameWithString: @"something"]],
                   @"Node not added to connection context");
    NSArray* inputNames = [deserialisedNode inputNames];
    STAssertTrue([inputNames count] == 2, @"Input names has wrong count %@", inputNames);
    STAssertTrue([inputNames containsObject: [LGSName nameWithConnectionString: @"a"]],
                 @"Input names has no a %@",
                 inputNames);
    STAssertTrue([inputNames containsObject: [LGSName nameWithConnectionString: @"b"]],
                 @"Input names has no b %@",
                 inputNames);
    NSArray* outputNames = [deserialisedNode outputNames];
    STAssertTrue([outputNames count] == 1, @"Output names has wrong count %@", outputNames);
    STAssertTrue([outputNames containsObject: [LGSName nameWithConnectionString: @"output"]],
                 @"Output names has no output %@",
                 outputNames);
}


-(void) testCopy
{
    NSString* testString = @""
    "   {"
    "\"name\" : \"something\","
    "\"nodeType\" : \"LGSXorGate\""
	"}";
    NSString* testCopyString = @""
    "   {"
    "\"name\" : \"somethingElse\","
    "\"nodeType\" : \"something\""
	"}";
    
    NSData* jsonData = [testString dataUsingEncoding: NSUTF8StringEncoding];
    NSError* error = nil;
    id jsonObject = [NSJSONSerialization JSONObjectWithData: jsonData
                                                    options: 0
                                                      error: &error];
    NSAssert1(jsonObject != nil, @"Invalid JSON string, %@", error);
    NSAssert1([jsonObject isKindOfClass: [NSDictionary class]],
              @"Invalid JSON object, %@", jsonObject);
    LGSConnectionContext* connectionContext = [[LGSConnectionContext alloc] init];
    id deserialisedNode = [LGSNode makeNodeFromDictionary: jsonObject
                                        connectionContext: connectionContext
                                                    error: &error];
    jsonData = [testCopyString dataUsingEncoding: NSUTF8StringEncoding];
    jsonObject = [NSJSONSerialization JSONObjectWithData: jsonData
                                                 options: 0
                                                   error: &error];
    NSAssert1(jsonObject != nil, @"Invalid JSON string, %@", error);
    NSAssert1([jsonObject isKindOfClass: [NSDictionary class]],
              @"Invalid JSON object, %@", jsonObject);
    deserialisedNode = [LGSNode makeNodeFromDictionary: jsonObject
                                     connectionContext: connectionContext
                                            	 error: &error];
    STAssertNotNil(deserialisedNode, @"Failed to deserialise, error %@", error);
    STAssertTrue([deserialisedNode isKindOfClass: [LGSXorGate class]],
                 @"Incorrect type %@",
                 deserialisedNode);
	STAssertNotNil([connectionContext nodeForName: [LGSName nameWithString: @"somethingElse"]],
                   @"Node not added to connection context");
}

static NSString* const MODULE_JSON = @""
"{"
"	\"nodeType\" : \"LGSModule\","
"	\"name\" : \"fullAdder\","
"   \"inputs\" : [\"a\", \"b\", \"cin\"],"
"   \"outputs\" : [\"bit\", \"cout\"],"
"   \"nodes\" : ["
"		{"
"			\"nodeType\" : \"LGSXorGate\","
"			\"name\" : \"aXorB\""
"		},"
"		{"
"			\"nodeType\" : \"LGSXorGate\","
"			\"name\" : \"aXorBXorC\""
"		},"
"		{"
"			\"nodeType\" : \"LGSAndGate\","
"			\"name\" : \"aAndB\""
"		},"
"		{"
"			\"nodeType\" : \"LGSAndGate\","
"			\"name\" : \"aXorBAndC\""
"		},"
"		{"
"			\"nodeType\" : \"LGSOrGate\","
"			\"name\" : \"cout\""
"		}"
"   ],"
"	\"connections\" : {"
"		\"aXorBXorC.a\" : \"aXorB.output\","
"		\"aXorBAndC.a\" : \"aXorB.output\","
"		\"cout.a\" : \"aXorBAndC.output\","
"		\"cout.b\" : \"aAndB.output\""
"	},"
"	\"inputMappings\" : {"
"		\"a\" : [ \"aXorB.a\", \"aAndB.a\"],"
"		\"b\" : [ \"aXorB.b\", \"aAndB.b\"],"
"		\"cin\" : [ \"aXorBXorC.b\", \"aXorBAndC.b\"]"
"	},"
"	\"outputMappings\" : {"
"		\"bit\" : \"aXorBXorC.output\","
"		\"cout\" : \"cout.output\""
"	}"
"}";

-(void) testCopyModule
{
    NSData* jsonData = [MODULE_JSON dataUsingEncoding: NSUTF8StringEncoding];
    NSError* error = nil;
    id jsonObject = [NSJSONSerialization JSONObjectWithData: jsonData
                                                    options: 0
                                                      error: &error];
    NSAssert1(jsonObject != nil, @"Invalid JSON string, %@", error);
    NSAssert1([jsonObject isKindOfClass: [NSDictionary class]],
              @"Invalid JSON object, %@", jsonObject);
    LGSConnectionContext* connectionContext = [[LGSConnectionContext alloc] init];
    id deserialisedNode = [LGSNode makeNodeFromDictionary: jsonObject
                                        connectionContext: connectionContext
                                                    error: &error];
    NSAssert1([deserialisedNode isKindOfClass:[LGSModule class]], @"Failed to deserialise, error %@", error);
    id copiedModule = [deserialisedNode copy];
    STAssertTrue([copiedModule isKindOfClass: [LGSModule class]],
                 @"Copied module is not a module %@", copiedModule);
    STAssertFalse(copiedModule == deserialisedNode, @"Copy is the same object");
    LGSNode* sampleNode = [copiedModule nodeForName: [LGSName nameWithString: @"aXorB"]];
    STAssertNotNil(sampleNode, @"Copied module has missing node %@", copiedModule);
    LGSEdge* inputEdge = [sampleNode input: [[sampleNode class] inputBName]];
    STAssertNotNil(inputEdge, @"Input mappings not done");
    NSSet* internalEdges = [sampleNode outputsForName: [[sampleNode class] outputName]];
    STAssertTrue([internalEdges count] == 2, @"Internal edges missing");
    LGSEdge* outputEdge = [[LGSEdge alloc] init];
    STAssertTrue([copiedModule addOutput: outputEdge
                                 forName: [LGSName nameWithConnectionString: @"bit"]],
                 @"Failed to connect output edge");
    STAssertNotNil([outputEdge input], @"Output edge has no input");
}

-(void) testDetectDuplication
{
    NSString* testString = @""
    "   {"
    "\"name\" : \"something\","
    "\"nodeType\" : \"LGSAndGate\""
	"}";
    
    NSData* jsonData = [testString dataUsingEncoding: NSUTF8StringEncoding];
    NSError* error = nil;
    id jsonObject = [NSJSONSerialization JSONObjectWithData: jsonData
                                                    options: 0
                                                      error: &error];
    NSAssert1(jsonObject != nil, @"Invalid JSON string, %@", error);
    NSAssert1([jsonObject isKindOfClass: [NSDictionary class]],
              @"Invalid JSON object, %@", jsonObject);
    LGSConnectionContext* connectionContext = [[LGSConnectionContext alloc] init];
    id deserialisedNode = [LGSNode makeNodeFromDictionary: jsonObject
                                        connectionContext: connectionContext
                                                    error: &error];
    NSAssert1(deserialisedNode, @"Failed to deserialise, error %@", error);
	STAssertNotNil([connectionContext nodeForName: [LGSName nameWithString: @"something"]],
                   @"Node not added to connection context");
    deserialisedNode = [LGSNode makeNodeFromDictionary: jsonObject
                                     connectionContext: connectionContext
                                                 error: &error];
    STAssertNil(deserialisedNode,
                @"Made a duplicate node in context %@",
                connectionContext);
}

@end
